#ifndef __GEN_H_
#define __GEN_H_

#include "type.h"
#include "symbol.h"

/**
	 OPCODE(INC,	 "++",					 Inc)
	 OPCODE(DEC,	 "--",					 Dec)
	 OPCODE(ADDR,	 "&",					 Address)
	 OPCODE(DEREF,	 "*",					 Deref)
	 OPCODE(EXTI1,	 "(int)(char)", 		 Cast)
 */
enum OPCode
{
#define OPCODE(code, name, func) code, 
#include "opcode.h" 
#undef OPCODE
};

struct basic_block_t;

/**
Intermediate Representation Instruction
see uildasm.c

#define DST  inst->opds[0]
#define SRC1 inst->opds[1]
#define SRC2 inst->opds[2]
	prev:	pointer to previous instruction
	next:	pointer to next instruction
	ty:		instruction operating type
	opcode:	operation code
	opds:	operands, at most three
 */
typedef struct irinst
{
	struct irinst *prev;
	struct irinst *next;
	type_t* ty;
	int opcode;
	symbol_t* opds[3];
} *IRInst;

/* control flow graph edge */
typedef struct cfgedge
{
	basic_block_t* bb;
	struct cfgedge *next;
} *CFGEdge;

/**
	basic block definition:
		prev:	pointer to previous basic block
		next:	pointer to next basic block
		sym:	symbol to represent basic block
		succs:	all the successors of this basic block
		preds:	all the predecessors of this basic block
		insth:	instruction list
		ninst:	number of instructions
		nsucc:	number of successors
		npred:	number of predecessors
 */
struct basic_block_t
{
	struct basic_block_t *prev;
	struct basic_block_t *next;
	symbol_t* sym;
	/* successors */
	CFGEdge succs;
	/* predecessors */
	CFGEdge preds;
	struct irinst insth;
	/* number of instructions */
	int ninst;
	/* number of successors */
	int nsucc;
	/* number of predecessors */
	int npred;
	int ref;
	#if 0		
	/* int no; */
	#endif
};

typedef struct ilarg
{
	symbol_t* sym;
	type_t* ty;
} *ILArg;

basic_block_t* CreateBBlock(void);
void   StartBBlock(basic_block_t* bb);

void GenerateMove(type_t* ty, symbol_t* dst, symbol_t* src);
void GenerateIndirectMove(type_t* ty, symbol_t* dst, symbol_t* src);
void GenerateAssign(type_t* ty, symbol_t* dst, int opcode, symbol_t* src1, symbol_t* src2);
void GenerateInc(type_t* ty, symbol_t* src);
void GenerateDec(type_t* ty, symbol_t* src);
void GenerateBranch(type_t* ty, basic_block_t* dstBB, int opcode, symbol_t* src1, symbol_t* src2);
void GenerateJump(basic_block_t* dstBB);
void GenerateIndirectJump(basic_block_t* *dstBBs, int len, symbol_t* index);
void GenerateReturn(type_t* ty, symbol_t* src);
void GenerateFunctionCall(type_t* ty, symbol_t* recv, symbol_t* faddr, void* args);
void GenerateClear(symbol_t* dst, int size);

void DefineTemp(symbol_t* t, int op, symbol_t* src1, symbol_t* src2);
symbol_t* AddressOf(symbol_t* sym);
symbol_t* Deref(type_t* ty, symbol_t* addr);
symbol_t* TryAddValue(type_t* ty, int op, symbol_t* src1, symbol_t* src2);
symbol_t* Simplify(type_t* ty, int op, symbol_t* src1, symbol_t* src2);

void DrawCFGEdge(basic_block_t* head, basic_block_t* tail);
void ExamineJump(basic_block_t* bb);
basic_block_t* TryMergeBBlock(basic_block_t* bb1, basic_block_t* bb2);
void Optimize(function_symbol_t* fsym);

extern basic_block_t* CurrentBB;
extern int OPMap[];

#endif

